// 专门用于显示外边缘线，包含了边缘线的相关数据（尤其是边的类型）。

import { ACTOR_TYPE, VTActorRenderType } from "../"
import { BActor } from "./BActor"
import { TEdge } from "./TEdge"
import { TLine } from "../Core/TLine"
import vtkActor from "@kitware/vtk.js/Rendering/Core/Actor"
import vtkMapper from "@kitware/vtk.js/Rendering/Core/Mapper"
import vtkDataArray from "@kitware/vtk.js/Common/Core/DataArray"
import { Vector3 } from "stl-typescript"
import { ColorMode } from "@kitware/vtk.js/Rendering/Core/Mapper/Constants"

// 后续需要提供函数根据边的类型显示边的颜色。
export class OutLineActor extends BActor {
  readonly type = ACTOR_TYPE.VT_ACTOR
  createdBy = "default"
  instance = vtkActor.newInstance()
  mapper: vtkMapper
  isMesh = false
  virtualLines: TLine[] = []

  edgeData: TEdge
  static readonly EDGE_COLOR = [0, 0, 0, 255] // 边默认色用黑色
  static readonly SHARED_EDGE_COLOR = [0, 255, 0, 255] // 共享边用绿色显示
  static readonly FREE_EDGE_COLOR = [255, 0, 0, 255] // 自由边用红色显示
  static readonly INTERNAL_EDGE_COLOR = [0, 0, 0, 255] // 黑色内部边颜色
  constructor(edgeData_ins: TEdge) {
    super()
    this.edgeData = edgeData_ins
    this.mapper = this.initMapper()
    this.instance.setMapper(this.mapper)
    this.createVirtualLine(edgeData_ins)
  }
  // 默认显示黑色线段
  hiddenEdgeColor() {
    if (!this.edgeData.edgeTypes || !this.edgeData.edgeLineNums) return
    const mapper = this.initMapper()
    const sc = mapper.getInputData().getCellData().getScalars()

    const edgeLen = this.edgeData.edgeTypes.length
    for (let i = 0; i < edgeLen; i++) {
      const startIdx = i == 0 ? 0 : this.edgeData.edgeLineNums[i - 1]
      const endIdx = this.edgeData.edgeLineNums[i]
      const rgba = OutLineActor.EDGE_COLOR
      for (let j = startIdx; j < endIdx; j++) {
        sc.setTuple(j, [...rgba])
      }
    }
    mapper.getInputData().getCellData().setScalars(sc)
    this.instance.setMapper(mapper)
    this.mapper = mapper
  }

  showEdgeColor() {
    if (!this.edgeData.edgeTypes || !this.edgeData.edgeLineNums) return
    const mapper = this.initMapper()
    const sc = mapper.getInputData().getCellData().getScalars()

    const edgeLen = this.edgeData.edgeTypes.length
    for (let i = 0; i < edgeLen; i++) {
      const startIdx = i == 0 ? 0 : this.edgeData.edgeLineNums[i - 1]
      const endIdx = this.edgeData.edgeLineNums[i]
      let rgba = OutLineActor.FREE_EDGE_COLOR
      if (this.edgeData.edgeTypes[i] === 0) {
        rgba = OutLineActor.SHARED_EDGE_COLOR
      } else if (this.edgeData.edgeTypes[i] === 2) {
        rgba = OutLineActor.INTERNAL_EDGE_COLOR
      }
      for (let j = startIdx; j < endIdx; j++) {
        sc.setTuple(j, [...rgba])
      }
    }
    mapper.getInputData().getCellData().setScalars(sc)
    this.instance.setMapper(mapper)
    this.mapper = mapper
  }
  searchEdgeByPoint(point: any, faceId: number) {
    // 依据faceId获取线上的点
    const edgeNodes = this.edgeData.faceEdgeNodeMap?.get(faceId)
    const minDistanceArray = []
    // debugger;
    for (let i = 0; i < edgeNodes.length; i++) {
      const edgeNodesMap = edgeNodes[i]
      const { edgeId, edgeStartIndex, edgeEndIndex, nodes } = edgeNodesMap
      let minDistance = Infinity
      if (nodes.length === 2) {
        // 如果是直线，计算点到线的距离
        for (let j = 0; j < nodes.length - 1; ) {
          const tempLine = new TLine(
            new Vector3(...nodes[j]),
            new Vector3(...nodes[j + 1])
          )
          const min = tempLine.distanceFromPoint(new Vector3(...point))
          minDistance = Math.min(minDistance, min)
          j += 2
        }
      }
      // TODO 如果是曲线，计算点到曲线上每个点的距离（暂时使用点与点距离计算）
      if (nodes.length > 2) {
        for (let j = 0; j < nodes.length - 1; j++) {
          const currentPoint = new Vector3(...nodes[j])
          const selectedPoint = new Vector3(...point)
          const min = selectedPoint.distanceTo(currentPoint)
          minDistance = Math.min(minDistance, min)
        }
      }
      minDistanceArray.push({
        minDistance,
        // edgeIndex,
        edgeStartIndex,
        edgeEndIndex,
        edgeId,
      })
    }
    const minEdge = minDistanceArray.sort(
      (a, b) => a.minDistance - b.minDistance
    )[0]
    const minEdgeStartIndex = minEdge.edgeStartIndex
    const minEdgeEndIndex = minEdge.edgeEndIndex
    return {
      selectedEdgeStartIndex: minEdgeStartIndex,
      selectedEdgeEndIndex: minEdgeEndIndex,
      selectedEdgeOriginColor: OutLineActor.EDGE_COLOR,
      selectedEdgeId: minEdge.edgeId,
    }
  }
  // 设置当前线颜色
  setEdgeColor(point: any, faceId: number, tempColor: number[]) {
    // 判断当前点的最近边，改变最近边颜色
    const selectedEdgeIndexDict = this.searchEdgeByPoint(point, faceId)
    const { selectedEdgeStartIndex, selectedEdgeEndIndex } =
      selectedEdgeIndexDict
    const mapper = this.initMapper()
    const polyData = mapper.getInputData()
    const sc = polyData.getCellData().getScalars()
    // 改变当前线条颜色
    for (let j = selectedEdgeStartIndex; j < selectedEdgeEndIndex; j++) {
      sc.setTuple(j, tempColor)
    }
    // 记录当前线条颜色
    selectedEdgeIndexDict.selectedEdgeOriginColor = tempColor
    mapper.getInputData().getCellData().setScalars(sc)
    this.instance.setMapper(mapper)
    this.mapper = mapper
    return selectedEdgeIndexDict
  }
  // 鼠标悬浮时线条颜色
  coverEdgeColor(
    point: any,
    faceId: number,
    tempColor: number[],
    lastEdgeStartIndex: number,
    lastEdgeEndIndex: number,
    lastEdgeOriginColor: number[]
  ) {
    // 移动时，需要判断当前点的最近边，改变最近边颜色，恢复上次边颜色
    const selectedEdgeIndexDict = this.searchEdgeByPoint(point, faceId)
    const { selectedEdgeStartIndex, selectedEdgeEndIndex } =
      selectedEdgeIndexDict
    const mapper = this.initMapper()
    const polyData = mapper.getInputData()
    const sc = polyData.getCellData().getScalars()
    const selectedEdgeOriginColor = sc.getTuple(selectedEdgeStartIndex)
    // 当前线条和上次计算的线条是否为同一根线条
    if (
      selectedEdgeStartIndex !== lastEdgeStartIndex ||
      selectedEdgeEndIndex !== lastEdgeEndIndex
    ) {
      // 改变当前线条颜色
      for (let j = selectedEdgeStartIndex; j < selectedEdgeEndIndex; j++) {
        sc.setTuple(j, tempColor)
      }
      for (let j = lastEdgeStartIndex; j < lastEdgeEndIndex; j++) {
        sc.setTuple(j, lastEdgeOriginColor)
      }
      selectedEdgeIndexDict.selectedEdgeOriginColor = selectedEdgeOriginColor
    } else {
      selectedEdgeIndexDict.selectedEdgeOriginColor = lastEdgeOriginColor
    }
    mapper.getInputData().getCellData().setScalars(sc)
    this.instance.setMapper(mapper)
    this.mapper = mapper
    return selectedEdgeIndexDict
  }

  /**
   * 
   * @param edgeIndex 线条索引
   * @param color 颜色 rgba数组 [0,0,0,255]
   */
  setEdgeColorByEdgeIndex(edgeIndex: number, color: number[]) {
    const mapper = this.initMapper()
    const sc = mapper.getInputData().getCellData().getScalars()
    sc.setTuple(edgeIndex, [...color])
    mapper.getInputData().getCellData().setScalars(sc)
    this.instance.setMapper(mapper)
    this.mapper = mapper
  }

  setEdgesColorByEdgeIndex(edgeIndexArr: number[], color: number[]) {
    const mapper = this.initMapper()
    const sc = mapper.getInputData().getCellData().getScalars()
    edgeIndexArr.forEach((id, index) => {
      sc.setTuple(id, [...color])
    })
    mapper.getInputData().getCellData().setScalars(sc)
    this.instance.setMapper(mapper)
    this.mapper = mapper
  }

  initMapper(): vtkMapper {
    const mapper = vtkMapper.newInstance({
      interpolateScalarsBeforeMapping: false,
      useLookupTableScalarRange: false,
      scalarVisibility: true,
      colorMode: ColorMode.DIRECT_SCALARS,
    })
    mapper.setScalarModeToUseCellData()
    mapper.setInputData(this.edgeData.polyData)
    const inputData = mapper.getInputData()
    if (!inputData.getCells()) {
      inputData.buildCells()
    }
    this.createCellColor(mapper, OutLineActor.EDGE_COLOR)
    return mapper
  }

  createCellColor(mapper: vtkMapper, tuple: number[] = [255, 255, 0, 255]) {
    const inputData = mapper.getInputData()
    const pd = inputData.getCellData()
    const colors = pd.getScalars()
    if (!colors) {
      const cellsInfo = inputData.getCells().get()
      const npts = cellsInfo.size
      const scalars = vtkDataArray.newInstance({
        name: "rgba",
        numberOfComponents: 4,
        values: new Uint8ClampedArray(npts * 4),
      })
      const rgba = tuple as number[]
      for (let i = 0; i < npts; ++i) {
        scalars.setTuple(i, [...rgba])
      }
      mapper.getInputData().getCellData().setScalars(scalars)
    }
  }

  setRenderType(type: VTActorRenderType) {
    if (type === VTActorRenderType.HIDDEN) {
      this.instance.setVisibility(false)
      return
    }
    this.instance.setVisibility(true)
    let representation: number
    let edgeVisibility: number

    switch (type) {
      case VTActorRenderType.POINTS:
        representation = 0
        edgeVisibility = 0
        break
      case VTActorRenderType.WIREFRAME:
        representation = 1
        edgeVisibility = 0
        break
      case VTActorRenderType.SURFACE:
        representation = 2
        edgeVisibility = 0
        break
      case VTActorRenderType.SURFACE_WITH_EDGE:
        representation = 2
        edgeVisibility = 1
        break
      default:
        representation = 2
        edgeVisibility = 0
        break
    }

    this.instance.getProperty().set({
      representation,
      edgeVisibility,
    })
  }

  get visible() {
    return this.instance.getVisibility()
  }

  set visible(vis: boolean) {
    this.instance.setVisibility(vis)
  }

  createVirtualLine(edgeData_ins: TEdge) {
    const { points, edgeTypes, edgeIds } = edgeData_ins
    if (
      points === undefined ||
      edgeTypes === undefined ||
      edgeIds === undefined
    )
      return
    for (let i = 0; i < points.length / 6; i++) {
      this.virtualLines.push(
        new TLine(
          new Vector3(points[6 * i], points[6 * i + 1], points[6 * i + 2]),
          new Vector3(points[6 * i + 3], points[6 * i + 4], points[6 * i + 5]),
          edgeTypes[i],
          edgeIds[i]
        )
      )
    }
  }
}
